package com.yanjiali.service.impl;

import com.yanjiali.constant.LoginConstant;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Package: com.yanjiali.service.impl
 * @Author: yanjiali
 * @Created: 2025/4/4 17:17
 * 通过实现 UserDetailsService 编写验证用户的逻辑，从数据库里验证
 */
@Service
public class UserServiceDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private JdbcTemplate jdbcTemplate;  //使用jdbc模板类操作数据库

    /**
     * 自实现登录逻辑
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        String loginType = requestAttributes.getRequest().getParameter("login_type");//区分是后台人员还是用户登录

        if(StringUtils.isEmpty(loginType)) {
            throw new AuthenticationServiceException("登录类型不能为null");
        }

        UserDetails userDetails = null; //存储获取到的用户信息

        try {
            String grantType = requestAttributes.getRequest().getParameter("grant_type");

            //在 jwt 里面存储的 username 实际是的 用户 id ，所需需要纠正 如果不是请求参数中会携带username
            if(LoginConstant.REFRESH_TOKEN.equals(grantType.toUpperCase())) {
                username = adjustUsername(username, loginType);
            }

            switch (loginType) {
                case LoginConstant.ADMIN_TYPE:
                    //管理员登录
                    userDetails = loadSysUserByUserName(username);
                    break;
                case LoginConstant.MEMBER_TYPE:
                    //普通用户登录
                    userDetails = loadMemberUserByUserName(username);
                    break;
                default:
                    throw new AuthenticationServiceException("暂不支持的登录方式" + loginType);
            }
        }catch (IncorrectResultSizeDataAccessException e) { //用户名不存在
            throw new UsernameNotFoundException("用户名" + username + "不存在");
        }

        return userDetails;
    }

    /**
     * 后台管理人员的登录
     * @param username
     * @return
     */
    private UserDetails loadSysUserByUserName(String username) {
        //1、使用用户名查询用户
        return jdbcTemplate.queryForObject(LoginConstant.QUERY_ADMIN_SQL, new RowMapper<User>() {
            @Override
            public User mapRow(ResultSet resultSet, int i) throws SQLException {
                if(resultSet == null) {
                    throw new UsernameNotFoundException("用户：" + username + "不存在");
                }

                long id = resultSet.getLong("id");
                String password = resultSet.getString("password");
                int status = resultSet.getInt("status");

                return new User(
                        String.valueOf(id), //使用id 代替 username
                        password,
                        status == 1,
                        true,
                        true,
                        true,
                        getSysUserPermission(id)
                );
            }
        }, username);
    }


    /**
     * 普通用户登录
     * @param username
     * @return
     */
    private UserDetails loadMemberUserByUserName(String username) {
        return jdbcTemplate.queryForObject(LoginConstant.QUERY_MEMBER_SQL, new RowMapper<User>() {
            @Override
            public User mapRow(ResultSet rs, int rowNum) throws SQLException {
                if(rs == null) {
                    throw new UsernameNotFoundException("用户：" + username + "不存在");
                }

                Long id = rs.getLong("id");
                String password = rs.getString("password");
                int status = rs.getInt("status");
                return new User(
                        String.valueOf(id),
                        password,
                        status == 1,
                        true,
                        true,
                        true,
                        getUserPermission(id)
                );
            }
        }, username, username, username);
    }


    /**
     * 通过用户的id查询用户权限
     * TODO 问题就在这个方法里面 处理好这里的SQL
     * @param id
     * @return
     */
    private Collection<? extends GrantedAuthority> getSysUserPermission(Long id) {
        String roleCode = jdbcTemplate.queryForObject(LoginConstant.QUERY_ROLE_CODE_SQL, String.class, id);
        List<String> permissions = null;    //存储权限信息
        if(LoginConstant.ADMIN_ROLE_CODE.equals(roleCode)) {    //用户是管理员登录中的管理员
            permissions = jdbcTemplate.queryForList(LoginConstant.QUERY_ALL_PERMISSIONS, String.class);
        }else { //用户是管理员登录中的普通后台业务人员
            permissions = jdbcTemplate.queryForList(LoginConstant.QUERY_PERMISSION_SQL, String.class, id);
        }

        if(permissions == null || permissions.isEmpty()) {
            return Collections.emptyList();
        }

        return permissions.stream()
                .distinct() //去重
                .map(perm -> new SimpleGrantedAuthority(perm))  //创建对应的子类对象
                .collect(Collectors.toSet());   //收集为集合
    }

    /**
     * TODO 补充一个普通用户获取权限
     * @param id
     * @return
     */
    private Collection<? extends GrantedAuthority> getUserPermission(Long id) {
        List<String> permissions = jdbcTemplate.queryForList(LoginConstant.MEMBER_TYPE_QUERY_PRIVILEGE, String.class, id);

        if(permissions == null || permissions.isEmpty()) {
            return Collections.emptyList();
        }

        return permissions.stream()
                .distinct() //去重
                .map(perm -> new SimpleGrantedAuthority(perm))  //创建对应的子类对象
                .collect(Collectors.toSet());   //收集为集合
    }

    /**
     * 纠正用户的用户名
     * queryForObject方法返回的泛型，通过第二个参数设置
     * @param username  通过用户id设置的用户名
     * @param loginType 用户的登录类型
     * @return 纠正后的用户名
     */
    private String adjustUsername(String username, String loginType) {
        if(LoginConstant.ADMIN_TYPE.equals(loginType)) {
            //管理员的纠正方式
            return jdbcTemplate.queryForObject(LoginConstant.QUERY_ADMIN_USER_WITH_ID, String.class, username);
        }

        if(LoginConstant.MEMBER_TYPE.equals(loginType)) {
            //会员的纠正方式
            return jdbcTemplate.queryForObject(LoginConstant.QUERY_MEMBER_USER_WITH_ID, String.class, username);
        }

        return username;
    }
}
